package com.sf.shiva.oms.common.util;


import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.sf.shiva.oms.common.exception.OmsException;
import com.sf.shiva.oms.common.exception.OmsRuntimeException;

/**
 * @description : JsonUtil工具类，<br>
 *              用于将对象转化成JSON以及将JSON 转化成对象，若发生异常，则记录错误日志信息
 * @author : 879149
 * @since : 1.0 HISTORY
 * 
 *        <pre>
 * ****************************************************************************
 *  ID   DATE            PERSON   REASON             DESC
 *  1    2016年1月28日              879149   Create/Modified    JsonUtil工具类
 *  2      2016年6月22日    866321        添加将JSON转为List的方法
 * ****************************************************************************
 *        </pre>
 */
public class JsonUtil {

    private JsonUtil(){}
    private static final Logger logger = LoggerFactory.getLogger(JsonUtil.class);

    private static final ObjectMapper objectMapper;
    /** 格式化时间的string */
    private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    static {
        objectMapper = new ObjectMapper();
        // 去掉默认的时间戳格式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        // 设置为中国北京时区
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
        // 空值不序列化
        objectMapper.setSerializationInclusion(Include.NON_NULL);
        // 反序列化时，属性不存在的兼容处理
        objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        // 序列化时，日期的统一格式
        objectMapper.setDateFormat(new SimpleDateFormat(DATE_TIME_FORMAT));

        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 单引号处理
        objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // KEY无引号处理
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    }

    /**
     * json 转换成 Object
     * 
     * @param json
     * @param clazz
     * @return
     */
    public static <T> T json2Object(String json, Class<T> clazz) {
        try {
            return objectMapper.readValue(json, clazz);
        } catch (IOException e) {
            logger.error("JsonUtil json2Object execute error", e);
            throw new OmsRuntimeException("analysis json error", e);
        }
    }

    public static <T> T json2Object(String json, TypeRef tr) {
        try {
            return objectMapper.readValue(json, tr.getType());
        } catch (IOException e) {
            logger.error("JsonUtil json2Object execute error", e);
            throw new OmsRuntimeException("analysis json error", e);
        }
    }

    /**
     * obj 转换成json
     * 
     * @param entity
     * @return
     */
    public static <T> String object2Json(T entity) {
        try {
            return objectMapper.writeValueAsString(entity);
        } catch (IOException e) {
            logger.error("JsonUtil object2Json execute error", e);
            throw new OmsRuntimeException("convert json error");
        }
    }

    /**
     * obj对象 转换成树型JSON
     * 
     * @param obj
     * @return
     */
    public static JsonNode object2TreeJson(Object obj) {
        try {
            return objectMapper.valueToTree(obj);
        } catch (Exception e) {
            logger.error("JsonUtil object2TreeJson execute error", e);
            throw new OmsRuntimeException("convert json error");
        }
    }

     /**
     * 将JSON字符串转换成List对象
     * 
     * @param <E>
     *            类
     * @param json
     *            JSON字符串
     * @param clazz
     *            业务对象Class
     * @return List对象
     * @author 866321
     */
    public static <E> List<E> json2List(Class<E> clazz, String json) {
        if (null == clazz || StringUtils.isEmpty(json)) {
            return Collections.emptyList();
        }
        List<E> list = null;
        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class,clazz);
            list = objectMapper.readValue(json, javaType);
        } catch (Exception e) {
            throw new OmsRuntimeException(e);
        }
        return list;
    }

    /**
     * json字符串转成Map
     * @param jsonStr
     * @return
     * @throws OmsException
     * @author 80002088
     * 2016年9月1日
     */
    public static Map<String, String> jsonToMap(String jsonStr) throws OmsException {
        JSONObject jsonObj = new JSONObject(jsonStr);
        Iterator<String> nameItr = jsonObj.keys();
        String name;
        Map<String, String> outMap = new HashMap<String, String>();
        while (nameItr.hasNext()) {
            name = nameItr.next();
            outMap.put(name, jsonObj.getString(name));
        }
        return outMap;
    }
    
    
    /**
     * 获取json中的对应key的值,可以是单个值，字符串，或者json对象，或者数组对象
     * @param json json字符串
     * @param key json中的key值
     * @return value
     */
    public static String getJsonValueByKey(String json,String key){
        int keyIndex=json.indexOf(key);
        if (keyIndex < 0) {
            return "";
        }
        int splitIndex=json.indexOf(":", keyIndex);
        String str=json.substring(splitIndex+1).trim();
        if('{'==str.charAt(0)){//json对象
            return getJsonValue(str,'{','}');//单个json对象，
        }else if('['==str.charAt(0)){
            return getJsonValue(str,'[',']');//数组对象
        }else{//单一value
            return getStrValue(str);
        }
    }
    
    /**
     * 获取非json 对象的值 （字符串和非字符串）
     * 1.字符串就按引号为边界截取
     * 2.单个值就按，或者}为边界截取
     * @param str
     * @return
     * @author 80002088
     * 2017年9月1日
     */
    private static String getStrValue(String str){
        if('"'==str.charAt(0)){//有引号的串
            for(int i=1,length=str.length();i<length;i++){
                char c1=str.charAt(i);
                char c2=str.charAt(i-1);
                if('"'==c1&&'\\'!=c2){
                    return str.substring(1,i);
                }
            }
        }else{//无引号的
            int index1=str.indexOf(",");
            int index2=str.indexOf("}");
            if(index1<index2&&index1>0){//在以,结尾的json中部
                return str.substring(0,index1);
            }else if(index2<index1&&index2>0 || index2>0&&index1<0){//在json串中部的}尾上 或 在json串尾部的}尾上
                return str.substring(0,index2);
            }
        }
        return "";
    }
    
    /**
     * 取字符串中的json对象或者数组对象
     * 1.将字符串中的干扰字符排除，所以对""内的不统计；
     * 2.使用开始字符prefixChar 找寻结束字符suffixChar，直到找到所有对，即为结束
     * @param str
     * @param prefixChar 开始字符 { 或 [
     * @param suffixChar 结束字符 } 或 ]
     * @return
     * @author 80002088
     * 2017年9月1日
     */
    private static String getJsonValue(String str,char prefixChar,char suffixChar){
        int length=str.length();
        int strCount=0;//""的计数
        int jsonCount=0;//json串的{}计数
        for(int i=0;i<length;i++){
            char c1=str.charAt(i);
            char c2=i==0?'"':str.charAt(i-1);
            if('"'==c1&&'\\'!=c2){
                strCount=strCount+1;
            }
            if(strCount%2==0){// 偶数代表有一对"",表示不在json之类,可以计数
                if(prefixChar==c1){
                    jsonCount=jsonCount+1;
                }else if(suffixChar==c1){
                    jsonCount=jsonCount-1;
                }
                if(jsonCount==0&&i>0){
                    return str.substring(0, i+1);
                }
            }
        }
        return "";
    }
    
}
